import axios from 'axios'
import qs from 'query-string'
import type {AxiosInstance, AxiosRequestConfig, AxiosResponse} from 'axios'
import {useUserStore} from '@/store';
import {getToken} from '@/utils/auth';
import {Message, Modal} from '@arco-design/web-vue';
import {SUESSCODE} from "@/types/const";

interface ICodeMessage {
    [propName: number]: string
}

const StatusCodeMessage: ICodeMessage = {
    20000: '服务器成功返回请求的数据',
    400: '请求错误(400)',
    401: '未授权，请重新登录(401)',
    403: '拒绝访问(403)',
    404: '请求出错(404)',
    408: '请求超时(408)',
    500: '服务器错误(500)',
    501: '服务未实现(501)',
    502: '网络错误(502)',
    503: '服务不可用(503)',
    504: '网络超时(504)',
}
const http: AxiosInstance = axios.create({
    baseURL: import.meta.env.VITE_API_BASE_URL,
    timeout: 30 * 1000,
})
// 请求拦截器

http.interceptors.request.use(
    // @ts-ignore
    (config: AxiosRequestConfig) => {
        const token = getToken()
        if (token) {
            if (!config.headers) {
                config.headers = {}
            }
            config.headers.Authorization = `Bearer ${token}`
        }
        return config
    },
    (error) => {
        return Promise.reject(error)
    },
)

// 响应拦截器
http.interceptors.response.use(
    (response: AxiosResponse) => {
        if (response.config.responseType === 'blob') {
            return response
        }
        const {data} = response
        const {code, msg} = data
        // 成功
        if (code === SUESSCODE) return response
        // Token 失效
        if (code === 401 && response.config.url !== '/auth/user/info') {
            Modal.error({
                title: '确认退出',
                content: '您已失效，可以取消以留在此页面，或重新登录',
                okText: '重新登陆',
                async onOk() {
                    const userStore = useUserStore();
                    await userStore.logout();
                    window.location.reload();
                },
            });
        } else {
            Message.error({
                content: data.msg || 'Error',
                duration: 5 * 1000,
            });
        }
        return Promise.reject(new Error(msg || '服务器端错误'))
    },
    (error) => {
        const response = Object.assign({}, error.response)
        response
        && Message.error({
            content: StatusCodeMessage[response.status] || '服务器暂时未响应，请刷新页面并重试。若无法解决，请联系管理员',
            duration: 5 * 1000,
        })
        return Promise.reject(error)
    },
)

const request = <T = unknown>(config: AxiosRequestConfig): Promise<ApiRes<T>> => {
    return new Promise((resolve, reject) => {
        http
            .request<T>(config)
            .then((res: AxiosResponse) => resolve(res.data))
            .catch((err: { msg: string }) => reject(err))
    })
}

const requestNative = <T = unknown>(config: AxiosRequestConfig): Promise<AxiosResponse> => {
    return new Promise((resolve, reject) => {
        http
            .request<T>(config)
            .then((res: AxiosResponse) => resolve(res))
            .catch((err: { msg: string }) => reject(err))
    })
}

const get = <T = any>(url: string, params?: object, config?: AxiosRequestConfig): Promise<ApiRes<T>> => {
    return request({
        method: 'get',
        url,
        params,
        paramsSerializer: (obj) => {
            return qs.stringify(obj)
        },
        ...config,
    })
}
const post = <T = any>(url: string, params?: object, config?: AxiosRequestConfig): Promise<ApiRes<T>> => {
    return request({
        method: 'post',
        url,
        data: params,
        ...config,
    })
}

const put = <T = any>(url: string, params?: object, config?: AxiosRequestConfig): Promise<ApiRes<T>> => {
    return request({
        method: 'put',
        url,
        data: params,
        ...config,
    })
}
const patch = <T = any>(url: string, params?: object, config?: AxiosRequestConfig): Promise<ApiRes<T>> => {
    return request({
        method: 'patch',
        url,
        data: params,
        ...config,
    })
}
const del = <T = any>(url: string, params?: object, config?: AxiosRequestConfig): Promise<ApiRes<T>> => {
    return request({
        method: 'delete',
        url,
        data: params,
        ...config,
    })
}
const download = (url: string, params?: object, config?: AxiosRequestConfig): Promise<AxiosResponse> => {
    return requestNative({
        method: 'get',
        url,
        responseType: 'blob',
        params,
        paramsSerializer: (obj) => {
            return qs.stringify(obj)
        },
        ...config,
    })
}
export default {get, post, put, patch, del, request, requestNative, download}
